import secrets
from typing import Annotated, Any, Literal, Optional, Union
from urllib.parse import quote_plus

from pydantic import AnyUrl, BeforeValidator, Field, field_validator, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


def parse_cors(v: Any) -> list[str] | str:
    """
    解析 CORS origins 配置。

    支持以下格式：
    - 字符串逗号分隔： "http://localhost, https://example.com"
    - 字符串列表： ["http://localhost", "https://example.com"]
    - 空列表或空字符串

    :param v: 环境变量输入值
    :return: 标准化的 origins 列表或原始字符串
    :raises ValueError: 无法解析的输入类型
    """
    if isinstance(v, str):
        if v.startswith("[") and v.endswith("]"):
            # 兼容 JSON 字符串形式（如 '[...]'），但通常由 Pydantic 自动处理
            return v
        return [origin.strip() for origin in v.split(",") if origin.strip()]
    elif isinstance(v, (list, str)):
        return v
    raise ValueError(f"Invalid CORS origins format: {v}")


class DatabaseConfig(BaseSettings):
    """数据库连接配置"""

    HOST: Optional[str] = Field(default=None, description="数据库主机地址")
    PORT: Optional[int] = Field(default=5432, description="数据库端口")
    DBUSER: Optional[str] = Field(default=None, description="数据库用户名")
    PASSWORD: Optional[str] = Field(default=None, description="数据库密码")
    DB: Optional[str] = Field(default=None, description="数据库名称")
    ECHO: bool = Field(default=False, description="是否输出 SQL 日志")
    TYPE: Literal["postgres", "sqlite"] = Field(
        default="postgres", description="数据库类型（仅支持 postgres / sqlite）"
    )

    # 连接池配置
    POOL_SIZE: int = Field(default=20, description="连接池大小")
    MAX_OVERFLOW: int = Field(default=10, description="最大溢出连接数")
    POOL_TIMEOUT: int = Field(default=30, description="获取连接超时时间（秒）")
    POOL_RECYCLE: int = Field(default=1800, description="连接回收间隔（秒）")

    model_config = SettingsConfigDict(
        env_prefix="DB_",  # 支持 DB_HOST, DB_PORT 等
        extra="ignore",
    )


class RedisConfig(BaseSettings):
    """Redis 连接配置"""

    HOST: Optional[str] = Field(default=None, description="Redis 主机地址")
    PORT: int = Field(default=6379, description="Redis 端口")
    DBUSER: Optional[str] = Field(default=None, description="Redis 用户名（通常为空）")
    PASSWORD: Optional[str] = Field(default=None, description="Redis 密码")
    DB: int = Field(default=0, description="Redis 数据库编号")
    TYPE: Literal["cache", "broker", "result"] = Field(default="cache", description="Redis 用途类型")

    model_config = SettingsConfigDict(
        env_prefix="REDIS_",  # 支持 REDIS_HOST, REDIS_PORT 等
        extra="ignore",
    )

    @property
    def redis_url(self) -> str:
        """
        生成 Redis 连接 URL。

        格式：
        - 无密码：redis://host:port/db
        - 有密码：redis://:password@host:port/db
        - 有用户名和密码：redis://username:password@host:port/db

        :return: Redis 连接字符串
        :raises ValueError: 缺少必要配置
        """
        if not self.HOST:
            raise ValueError("Redis HOST is required")

        # 构建认证部分
        auth_part = ""
        if self.PASSWORD:
            # 对密码进行 URL 编码，防止特殊字符导致解析失败
            safe_password = quote_plus(self.PASSWORD)
            if self.DBUSER:
                safe_username = quote_plus(self.DBUSER)
                auth_part = f"{safe_username}:{safe_password}@"
            else:
                auth_part = f":{safe_password}@"
        elif self.DBUSER:
            safe_username = quote_plus(self.DBUSER)
            auth_part = f"{safe_username}@"

        return f"redis://{auth_part}{self.HOST}:{self.PORT}/{self.DB}"


class Settings(BaseSettings):
    """应用程序主配置类"""

    # ─────────────── 基础配置 ───────────────
    PROJECT_NAME: str = Field(default="GoldenChannelERP", description="项目名称")
    VERSION: str = Field(default="0.1.0", description="应用版本号")
    DEBUG: bool = Field(default=True, description="是否启用调试模式")
    HOST: str = Field(default="0.0.0.0", description="服务监听地址")
    PORT: int = Field(default=8000, description="服务监听端口")
    API_V1_STR: str = Field(default="/api/v1", description="API V1 路由前缀")
    WORKERS: int = Field(default=1, description="Uvicorn 工作进程数")
    ADMIN_ROLE_CODE: str = Field(default="ROOT", description="管理员角色CODE")

    CORS_ORIGINS: Annotated[Union[list[AnyUrl], str], BeforeValidator(parse_cors)] = Field(
        default_factory=list,
        description="CORS 允许的源列表（支持逗号分隔字符串或 URL 列表）",
    )

    # ─────────────── 日志配置 ───────────────
    LOG_LEVEL: str = Field(
        default="INFO",
        description="应用日志级别（DEBUG/INFO/WARNING/ERROR/CRITICAL）",
    )
    LOG_DIR: str = Field(default="logs", description="日志文件存储目录")
    LOG_BACKUP_COUNT: int = Field(default=7, description="日志文件保留天数")
    LOG_MAX_BYTES: int = Field(default=10 * 1024 * 1024, description="日志文件最大大小，默认10MB")
    THIRD_PARTY_LOG_LEVELS: dict[str, str] = Field(
        default_factory=lambda: {"passlib": "INFO", "uvicorn": "WARNING"},
        description="第三方库日志级别覆盖配置",
    )

    # ─────────────── 模板文件目录配置 ───────────────
    TEMPLATES_DIR: str = Field(default="templates", description="模板文件目录")

    # ─────────────── 安全与认证 ───────────────
    SECRET_KEY: str = Field(
        default_factory=lambda: secrets.token_urlsafe(64),
        description="JWT 签名密钥（自动生成，建议生产环境通过环境变量设置）",
    )
    ALGORITHM: str = Field(default="HS256", description="JWT 签名算法")

    # ─────────────── 缓存键前缀与命名 ───────────────
    KEY_CACHE_PREFIX: str = Field(default="hmb:gce", description="所有缓存键的统一前缀")
    # 以下字段将在 model_validator 中自动拼接前缀
    KEY_AUTH_TOKEN: str = Field(default="auth:token")
    KEY_AUTH_USER_ROLE: str = Field(default="auth:user:role")
    KEY_AUTH_USER_PERMISSION: str = Field(default="auth:user:permission")
    KEY_ACCESS_TOKEN_USER: str = Field(default="auth:token:access")
    KEY_REFRESH_TOKEN_USER: str = Field(default="auth:token:refresh")

    KEY_RATE_LIMITER: str = Field(default="rate_limiter:ip")
    KEY_LOCK_RESUBMIT: str = Field(default="lock:resubmit")

    KEY_USER_ACCESS_TOKEN: str = Field(default="auth:user:access")
    KEY_USER_REFRESH_TOKEN: str = Field(default="auth:user:refresh")
    KEY_BLACKLIST_TOKEN: str = Field(default="auth:token:blacklist")
    KEY_CAPTCHA_IMAGE_CODE: str = Field(default="captcha:image")
    KEY_CAPTCHA_SMS_LOGIN_CODE: str = Field(default="captcha:sms:login")
    KEY_CAPTCHA_SMS_REGISTER_CODE: str = Field(default="captcha:sms:register")
    KEY_CAPTCHA_MOBILE_CODE: str = Field(default="captcha:mobile")
    KEY_CAPTCHA_EMAIL_CODE: str = Field(default="captcha:email")
    KEY_SYSTEM_CONFIG: str = Field(default="system:config")
    KEY_SYSTEM_ROLE_PERMS: str = Field(default="system:role:perms")

    # ─────────────── 数据库与缓存 ───────────────
    GCE_DB: DatabaseConfig = Field(default_factory=DatabaseConfig, description="主数据库配置")
    REDIS_CACHE: Optional[RedisConfig] = Field(default=None, description="Redis 缓存配置（可选）")

    # ─────────────── 验证码配置 ───────────────
    CAPTCHA_TYPE: Literal["arithmetic", "alphanumeric"] = Field(default="arithmetic", description="验证码类型")
    CAPTCHA_TIMEOUT: int = Field(default=300, description="验证码有效期（秒）")
    CAPTCHA_FONT_PATH: str = Field(
        default="/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
        description="验证码字体文件路径",
    )
    CAPTCHA_INTERFERENCE: int = Field(default=5, description="干扰线数量")
    CAPTCHA_ENABLED: bool = Field(default=False, description="是否启用验证码")

    # ─────────────── Token 生命周期 ───────────────
    ACCESS_TOKEN_LIFETIME: int = Field(default=30, description="访问令牌有效期（分钟）")
    REFRESH_TOKEN_LIFETIME: int = Field(default=7, description="刷新令牌有效期（天）")
    USER_BLACKLIST_TTL: int = Field(default=30, description="用户黑名单有效期（天）")

    # ─────────────── 验证与后处理 ───────────────
    @model_validator(mode="after")
    def validate_cache_keys(self) -> "Settings":
        """
        自动为所有缓存键添加统一前缀（如 'hmb:gce:'），
        避免手动维护前缀，确保键空间隔离。
        仅当字段值不为空且未以当前前缀开头时才拼接。
        """
        prefix = self.KEY_CACHE_PREFIX
        cache_fields = [
            "KEY_RATE_LIMITER",
            "KEY_LOCK_RESUBMIT",
            "KEY_ACCESS_TOKEN_USER",
            "KEY_REFRESH_TOKEN_USER",
            "KEY_USER_ACCESS_TOKEN",
            "KEY_USER_REFRESH_TOKEN",
            "KEY_BLACKLIST_TOKEN",
            "KEY_CAPTCHA_IMAGE_CODE",
            "KEY_CAPTCHA_SMS_LOGIN_CODE",
            "KEY_CAPTCHA_SMS_REGISTER_CODE",
            "KEY_CAPTCHA_MOBILE_CODE",
            "KEY_CAPTCHA_EMAIL_CODE",
            "KEY_SYSTEM_CONFIG",
            "KEY_SYSTEM_ROLE_PERMS",
            "KEY_AUTH_TOKEN",
        ]

        for field_name in cache_fields:
            current_value: str = getattr(self, field_name)
            if current_value and not current_value.startswith(f"{prefix}:"):
                setattr(self, field_name, f"{prefix}:{current_value}")

        return self

    @field_validator("SECRET_KEY")
    @classmethod
    def ensure_secret_key_not_empty(cls, v: str) -> str:
        if not v or len(v) < 32:
            raise ValueError("SECRET_KEY 必须足够长且非空（建议 ≥64 字符）")
        return v

    # TEMPLATES_DIR 不存在，就创建
    @field_validator("TEMPLATES_DIR", mode="after")
    @classmethod
    def ensure_templates_dir_exists(cls, v: str) -> str:
        import os

        if not os.path.exists(v):
            os.makedirs(v)
        return v

    # ─────────────── 数据库 URI 构建 ───────────────
    @property
    def SQLALCHEMY_DATABASE_URI(self) -> str:
        """
        同步 SQLAlchemy 数据库连接 URI。
        仅支持 PostgreSQL 和 SQLite。
        """
        db = self.GCE_DB
        if db.TYPE == "postgres":
            if not all([db.HOST, db.DBUSER, db.PASSWORD, db.DB]):
                raise ValueError("PostgreSQL 配置缺失必要字段：HOST, USERNAME, PASSWORD, DB")
            return f"postgresql+psycopg2://{db.DBUSER}:{db.PASSWORD}" f"@{db.HOST}:{db.PORT}/{db.DB}"
        elif db.TYPE == "sqlite":
            db_path = db.DB or "app.db"
            return f"sqlite:///{db_path}"
        else:
            raise ValueError(f"不支持的数据库类型: {db.TYPE}")

    @property
    def SQLALCHEMY_ASYNC_DATABASE_URI(self) -> str:
        """
        异步 SQLAlchemy 数据库连接 URI。
        """
        db = self.GCE_DB
        if db.TYPE == "postgres":
            if not all([db.HOST, db.DBUSER, db.PASSWORD, db.DB]):
                raise ValueError("PostgreSQL 配置缺失必要字段")
            return f"postgresql+asyncpg://{db.DBUSER}:{db.PASSWORD}" f"@{db.HOST}:{db.PORT}/{db.DB}"
        elif db.TYPE == "sqlite":
            db_path = db.DB or "app.db"
            return f"sqlite+aiosqlite:///{db_path}"
        else:
            raise ValueError(f"不支持的异步数据库类型: {db.TYPE}")

    # ─────────────── Pydantic 设置 ───────────────
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
        env_nested_delimiter="__",  # 支持 GCE_DB__HOST, REDIS_CACHE__HOST 等
        env_ignore_empty=True,
    )
